home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / gfx / x11 / twm_930531.lha / twm / menus.c < prev    next >
C/C++ Source or Header  |  1993-05-30  |  71KB  |  2,961 lines

  1. /*****************************************************************************/
  2. /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
  3. /**                          Salt Lake City, Utah                           **/
  4. /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
  5. /**                        Cambridge, Massachusetts                         **/
  6. /**                                                                         **/
  7. /**                           All Rights Reserved                           **/
  8. /**                                                                         **/
  9. /**    Permission to use, copy, modify, and distribute this software and    **/
  10. /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
  11. /**    granted, provided that the above copyright notice appear  in  all    **/
  12. /**    copies and that both  that  copyright  notice  and  this  permis-    **/
  13. /**    sion  notice appear in supporting  documentation,  and  that  the    **/
  14. /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
  15. /**    in publicity pertaining to distribution of the  software  without    **/
  16. /**    specific, written prior permission.                                  **/
  17. /**                                                                         **/
  18. /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
  19. /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
  20. /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
  21. /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
  22. /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
  23. /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
  24. /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
  25. /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
  26. /*****************************************************************************/
  27.  
  28.  
  29. /***********************************************************************
  30.  *
  31.  * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
  32.  *
  33.  * twm menu code
  34.  *
  35.  * 17-Nov-87 Thomas E. LaStrange        File created
  36.  *
  37.  ***********************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include <signal.h>
  41. #include <X11/Xos.h>
  42. #include "twm.h"
  43. #include "gc.h"
  44. #include "menus.h"
  45. #include "resize.h"
  46. #include "events.h"
  47. #include "util.h"
  48. #include "parse.h"
  49. #include "gram.h"
  50. #include "screen.h"
  51. #include <X11/Xmu/CharSet.h>
  52. #include <X11/bitmaps/menu12>
  53. #include "version.h"
  54.  
  55. extern XEvent Event;
  56.  
  57. int RootFunction = NULL;
  58. MenuRoot *ActiveMenu = NULL;        /* the active menu */
  59. MenuItem *ActiveItem = NULL;        /* the active menu item */
  60. int MoveFunction;            /* either F_MOVE or F_FORCEMOVE */
  61. int WindowMoved = FALSE;
  62. int menuFromFrameOrWindowOrTitlebar = FALSE;
  63.  
  64. int ConstMove = FALSE;        /* constrained move variables */
  65. int ConstMoveDir;
  66. int ConstMoveX;
  67. int ConstMoveY;
  68. int ConstMoveXL;
  69. int ConstMoveXR;
  70. int ConstMoveYT;
  71. int ConstMoveYB;
  72.  
  73. /* Globals used to keep track of whether the mouse has moved during
  74.    a resize function. */
  75. int ResizeOrigX;
  76. int ResizeOrigY;
  77.  
  78. int MenuDepth = 0;        /* number of menus up */
  79. static struct {
  80.     int x;
  81.     int y;
  82. } MenuOrigins[MAXMENUDEPTH];
  83. static Cursor LastCursor;
  84.  
  85. void WarpAlongRing(), WarpToWindow();
  86.  
  87. extern char *Action;
  88. extern int Context;
  89. extern TwmWindow *ButtonWindow, *Tmp_win;
  90. extern XEvent Event, ButtonEvent;
  91. extern char *InitFile;
  92. static void Identify();
  93.  
  94. #define SHADOWWIDTH 5            /* in pixels */
  95.  
  96.  
  97.  
  98. /***********************************************************************
  99.  *
  100.  *  Procedure:
  101.  *    InitMenus - initialize menu roots
  102.  *
  103.  ***********************************************************************
  104.  */
  105.  
  106. void
  107. InitMenus()
  108. {
  109.     int i, j, k;
  110.     FuncKey *key, *tmp;
  111.  
  112.     for (i = 0; i < MAX_BUTTONS+1; i++)
  113.     for (j = 0; j < NUM_CONTEXTS; j++)
  114.         for (k = 0; k < MOD_SIZE; k++)
  115.         {
  116.         Scr->Mouse[i][j][k].func = NULL;
  117.         Scr->Mouse[i][j][k].item = NULL;
  118.         }
  119.  
  120.     Scr->DefaultFunction.func = NULL;
  121.     Scr->WindowFunction.func = NULL;
  122.  
  123.     if (FirstScreen)
  124.     {
  125.     for (key = Scr->FuncKeyRoot.next; key != NULL;)
  126.     {
  127.         free(key->name);
  128.         tmp = key;
  129.         key = key->next;
  130.         free((char *) tmp);
  131.     }
  132.     Scr->FuncKeyRoot.next = NULL;
  133.     }
  134.  
  135. }
  136.  
  137.  
  138.  
  139. /***********************************************************************
  140.  *
  141.  *  Procedure:
  142.  *    AddFuncKey - add a function key to the list
  143.  *
  144.  *  Inputs:
  145.  *    name    - the name of the key
  146.  *    cont    - the context to look for the key press in
  147.  *    mods    - modifier keys that need to be pressed
  148.  *    func    - the function to perform
  149.  *    win_name- the window name (if any)
  150.  *    action    - the action string associated with the function (if any)
  151.  *
  152.  ***********************************************************************
  153.  */
  154.  
  155. Bool AddFuncKey (name, cont, mods, func, win_name, action)
  156.     char *name;
  157.     int cont, mods, func;
  158.     char *win_name;
  159.     char *action;
  160. {
  161.     FuncKey *tmp;
  162.     KeySym keysym;
  163.     KeyCode keycode;
  164.  
  165.     /*
  166.      * Don't let a 0 keycode go through, since that means AnyKey to the
  167.      * XGrabKey call in GrabKeys().
  168.      */
  169.     if ((keysym = XStringToKeysym(name)) == NoSymbol ||
  170.     (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
  171.     {
  172.     return False;
  173.     }
  174.  
  175.     /* see if there already is a key defined for this context */
  176.     for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
  177.     {
  178.     if (tmp->keysym == keysym &&
  179.         tmp->cont == cont &&
  180.         tmp->mods == mods)
  181.         break;
  182.     }
  183.  
  184.     if (tmp == NULL)
  185.     {
  186.     tmp = (FuncKey *) malloc(sizeof(FuncKey));
  187.     tmp->next = Scr->FuncKeyRoot.next;
  188.     Scr->FuncKeyRoot.next = tmp;
  189.     }
  190.  
  191.     tmp->name = name;
  192.     tmp->keysym = keysym;
  193.     tmp->keycode = keycode;
  194.     tmp->cont = cont;
  195.     tmp->mods = mods;
  196.     tmp->func = func;
  197.     tmp->win_name = win_name;
  198.     tmp->action = action;
  199.  
  200.     return True;
  201. }
  202.  
  203.  
  204.  
  205. int CreateTitleButton (name, func, action, menuroot, rightside, append)
  206.     char *name;
  207.     int func;
  208.     char *action;
  209.     MenuRoot *menuroot;
  210.     Bool rightside;
  211.     Bool append;
  212. {
  213.     TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
  214.  
  215.     if (!tb) {
  216.     fprintf (stderr,
  217.          "%s:  unable to allocate %d bytes for title button\n",
  218.          ProgramName, sizeof(TitleButton));
  219.     return 0;
  220.     }
  221.  
  222.     tb->next = NULL;
  223.     tb->name = name;            /* note that we are not copying */
  224.     tb->bitmap = None;            /* WARNING, values not set yet */
  225.     tb->width = 0;            /* see InitTitlebarButtons */
  226.     tb->height = 0;            /* ditto */
  227.     tb->func = func;
  228.     tb->action = action;
  229.     tb->menuroot = menuroot;
  230.     tb->rightside = rightside;
  231.     if (rightside) {
  232.     Scr->TBInfo.nright++;
  233.     } else {
  234.     Scr->TBInfo.nleft++;
  235.     }
  236.  
  237.     /*
  238.      * Cases for list:
  239.      * 
  240.      *     1.  empty list, prepend left       put at head of list
  241.      *     2.  append left, prepend right     put in between left and right
  242.      *     3.  append right                   put at tail of list
  243.      *
  244.      * Do not refer to widths and heights yet since buttons not created
  245.      * (since fonts not loaded and heights not known).
  246.      */
  247.     if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {    /* 1 */
  248.     tb->next = Scr->TBInfo.head;
  249.     Scr->TBInfo.head = tb;
  250.     } else if (append && rightside) {    /* 3 */
  251.     register TitleButton *t;
  252.     for /* SUPPRESS 530 */
  253.       (t = Scr->TBInfo.head; t->next; t = t->next);
  254.     t->next = tb;
  255.     tb->next = NULL;
  256.     } else {                /* 2 */
  257.     register TitleButton *t, *prev = NULL;
  258.     for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
  259.         prev = t;
  260.     }
  261.     if (prev) {
  262.         tb->next = prev->next;
  263.         prev->next = tb;
  264.     } else {
  265.         tb->next = Scr->TBInfo.head;
  266.         Scr->TBInfo.head = tb;
  267.     }
  268.     }
  269.  
  270.     return 1;
  271. }
  272.  
  273.  
  274.  
  275. /*
  276.  * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
  277.  * button.  If we can't find the button, then put in a question; if we can't
  278.  * find the question mark, something is wrong and we are probably going to be
  279.  * in trouble later on.
  280.  */
  281. void InitTitlebarButtons ()
  282. {
  283.     TitleButton *tb;
  284.     int h;
  285.  
  286.     /*
  287.      * initialize dimensions
  288.      */
  289.     Scr->TBInfo.width = (Scr->TitleHeight -
  290.              2 * (Scr->FramePadding + Scr->ButtonIndent));
  291.     Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
  292.                ? ((Scr->TitlePadding + 1) / 2) : 1);
  293.     h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
  294.  
  295.     /*
  296.      * add in some useful buttons and bindings so that novices can still
  297.      * use the system.
  298.      */
  299.     if (!Scr->NoDefaults) {
  300.     /* insert extra buttons */
  301.     if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
  302.                 False, False)) {
  303.         fprintf (stderr, "%s:  unable to add iconify button\n",
  304.              ProgramName);
  305.     }
  306.     if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
  307.                 True, True)) {
  308.         fprintf (stderr, "%s:  unable to add resize button\n",
  309.              ProgramName);
  310.     }
  311.     AddDefaultBindings ();
  312.     }
  313.     ComputeCommonTitleOffsets ();
  314.  
  315.     /*
  316.      * load in images and do appropriate centering
  317.      */
  318.  
  319.     for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
  320.     tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
  321.     if (!tb->bitmap) {
  322.         tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
  323.         if (!tb->bitmap) {        /* cannot happen (see util.c) */
  324.         fprintf (stderr,
  325.              "%s:  unable to add titlebar button \"%s\"\n",
  326.              ProgramName, tb->name);
  327.         }
  328.     }
  329.  
  330.     tb->dstx = (h - tb->width + 1) / 2;
  331.     if (tb->dstx < 0) {        /* clip to minimize copying */
  332.         tb->srcx = -(tb->dstx);
  333.         tb->width = h;
  334.         tb->dstx = 0;
  335.     } else {
  336.         tb->srcx = 0;
  337.     }
  338.     tb->dsty = (h - tb->height + 1) / 2;
  339.     if (tb->dsty < 0) {
  340.         tb->srcy = -(tb->dsty);
  341.         tb->height = h;
  342.         tb->dsty = 0;
  343.     } else {
  344.         tb->srcy = 0;
  345.     }
  346.     }
  347. }
  348.  
  349.  
  350.  
  351. PaintEntry(mr, mi, exposure)
  352. MenuRoot *mr;
  353. MenuItem *mi;
  354. int exposure;
  355. {
  356.     int y_offset;
  357.     int text_y;
  358.     GC gc;
  359.  
  360. #ifdef DEBUG_MENUS
  361.     fprintf(stderr, "Paint entry\n");
  362. #endif
  363.     y_offset = mi->item_num * Scr->EntryHeight;
  364.     text_y = y_offset + Scr->MenuFont.y;
  365.  
  366.     if (mi->func != F_TITLE)
  367.     {
  368.     int x, y;
  369.  
  370.     if (mi->state)
  371.     {
  372.         XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
  373.  
  374.         XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
  375.         mr->width, Scr->EntryHeight);
  376.  
  377.         FBF(mi->hi_fore, mi->hi_back, Scr->MenuFont.font->fid);
  378.  
  379.         XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
  380.         text_y, mi->item, mi->strlen);
  381.  
  382.         gc = Scr->NormalGC;
  383.     }
  384.     else
  385.     {
  386.         if (mi->user_colors || !exposure)
  387.         {
  388.         XSetForeground(dpy, Scr->NormalGC, mi->back);
  389.  
  390.         XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
  391.             mr->width, Scr->EntryHeight);
  392.  
  393.         FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
  394.         gc = Scr->NormalGC;
  395.         }
  396.         else
  397.         gc = Scr->MenuGC;
  398.  
  399.         XDrawString(dpy, mr->w, gc, mi->x,
  400.         text_y, mi->item, mi->strlen);
  401.     }
  402.  
  403.     if (mi->func == F_MENU)
  404.     {
  405.         /* create the pull right pixmap if needed */
  406.         if (Scr->pullPm == None)
  407.         {
  408.         Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
  409.                          &Scr->pullW, &Scr->pullH);
  410.         }
  411.         x = mr->width - Scr->pullW - 5;
  412.         y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
  413.         XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
  414.         Scr->pullW, Scr->pullH, x, y, 1);
  415.     }
  416.     }
  417.     else
  418.     {
  419.     int y;
  420.  
  421.     XSetForeground(dpy, Scr->NormalGC, mi->back);
  422.  
  423.     /* fill the rectangle with the title background color */
  424.     XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
  425.         mr->width, Scr->EntryHeight);
  426.  
  427.     {
  428.         XSetForeground(dpy, Scr->NormalGC, mi->fore);
  429.         /* now draw the dividing lines */
  430.         if (y_offset)
  431.           XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
  432.              mr->width, y_offset);
  433.         y = ((mi->item_num+1) * Scr->EntryHeight)-1;
  434.         XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
  435.     }
  436.  
  437.     FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
  438.     /* finally render the title */
  439.     XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
  440.         text_y, mi->item, mi->strlen);
  441.     }
  442. }
  443.     
  444.  
  445.  
  446. PaintMenu(mr, e)
  447. MenuRoot *mr;
  448. XEvent *e;
  449. {
  450.     MenuItem *mi;
  451.  
  452.     for (mi = mr->first; mi != NULL; mi = mi->next)
  453.     {
  454.     int y_offset = mi->item_num * Scr->EntryHeight;
  455.  
  456.     /* be smart about handling the expose, redraw only the entries
  457.      * that we need to
  458.      */
  459.     if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
  460.         (e->xexpose.y + e->xexpose.height) > y_offset)
  461.     {
  462.         PaintEntry(mr, mi, True);
  463.     }
  464.     }
  465.     XSync(dpy, 0);
  466. }
  467.  
  468.  
  469.  
  470. static Bool fromMenu;
  471.  
  472. UpdateMenu()
  473. {
  474.     MenuItem *mi;
  475.     int i, x, y, x_root, y_root, entry;
  476.     int done;
  477.     MenuItem *badItem = NULL;
  478.  
  479.     fromMenu = TRUE;
  480.  
  481.     while (TRUE)
  482.     {
  483.     /* block until there is an event */
  484.         if (!menuFromFrameOrWindowOrTitlebar) {
  485.       XMaskEvent(dpy,
  486.              ButtonPressMask | ButtonReleaseMask |
  487.              EnterWindowMask | ExposureMask |
  488.              VisibilityChangeMask | LeaveWindowMask |
  489.              ButtonMotionMask, &Event);
  490.     }
  491.     if (Event.type == MotionNotify) {
  492.         /* discard any extra motion events before a release */
  493.         while(XCheckMaskEvent(dpy,
  494.         ButtonMotionMask | ButtonReleaseMask, &Event))
  495.         if (Event.type == ButtonRelease)
  496.             break;
  497.     }
  498.  
  499.     if (!DispatchEvent ())
  500.         continue;
  501.  
  502.     if (Event.type == ButtonRelease || Cancel) {
  503.       menuFromFrameOrWindowOrTitlebar = FALSE;
  504.       fromMenu = FALSE;
  505.       return;
  506.     }
  507.  
  508.     if (Event.type != MotionNotify)
  509.         continue;
  510.  
  511.     done = FALSE;
  512.     XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
  513.         &x_root, &y_root, &x, &y, &JunkMask);
  514.  
  515.     /* if we haven't recieved the enter notify yet, wait */
  516.     if (ActiveMenu && !ActiveMenu->entered)
  517.         continue;
  518.  
  519.     XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
  520.  
  521.     if (x < 0 || y < 0 ||
  522.         x >= ActiveMenu->width || y >= ActiveMenu->height)
  523.     {
  524.         if (ActiveItem && ActiveItem->func != F_TITLE)
  525.         {
  526.         ActiveItem->state = 0;
  527.         PaintEntry(ActiveMenu, ActiveItem, False);
  528.         }
  529.         ActiveItem = NULL;
  530.         continue;
  531.     }
  532.  
  533.     /* look for the entry that the mouse is in */
  534.     entry = y / Scr->EntryHeight;
  535.     for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
  536.     {
  537.         if (i == entry)
  538.         break;
  539.     }
  540.  
  541.     /* if there is an active item, we might have to turn it off */
  542.     if (ActiveItem)
  543.     {
  544.         /* is the active item the one we are on ? */
  545.         if (ActiveItem->item_num == entry && ActiveItem->state)
  546.         done = TRUE;
  547.  
  548.         /* if we weren't on the active entry, let's turn the old
  549.          * active one off 
  550.          */
  551.         if (!done && ActiveItem->func != F_TITLE)
  552.         {
  553.         ActiveItem->state = 0;
  554.         PaintEntry(ActiveMenu, ActiveItem, False);
  555.         }
  556.     }
  557.  
  558.     /* if we weren't on the active item, change the active item and turn
  559.      * it on 
  560.      */
  561.     if (!done)
  562.     {
  563.         ActiveItem = mi;
  564.         if (ActiveItem->func != F_TITLE && !ActiveItem->state)
  565.         {
  566.         ActiveItem->state = 1;
  567.         PaintEntry(ActiveMenu, ActiveItem, False);
  568.         }
  569.     }
  570.  
  571.     /* now check to see if we were over the arrow of a pull right entry */
  572.     if (ActiveItem->func == F_MENU && 
  573.         ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
  574.     {
  575.         MenuRoot *save = ActiveMenu;
  576.         int savex = MenuOrigins[MenuDepth - 1].x; 
  577.         int savey = MenuOrigins[MenuDepth - 1].y;
  578.  
  579.         if (MenuDepth < MAXMENUDEPTH) {
  580.         PopUpMenu (ActiveItem->sub, 
  581.                (savex + (ActiveMenu->width >> 1)), 
  582.                (savey + ActiveItem->item_num * Scr->EntryHeight)
  583.                /*(savey + ActiveItem->item_num * Scr->EntryHeight +
  584.                 (Scr->EntryHeight >> 1))*/, False);
  585.         } else if (!badItem) {
  586.         XBell (dpy, 0);
  587.         badItem = ActiveItem;
  588.         }
  589.  
  590.         /* if the menu did get popped up, unhighlight the active item */
  591.         if (save != ActiveMenu && ActiveItem->state)
  592.         {
  593.         ActiveItem->state = 0;
  594.         PaintEntry(save, ActiveItem, False);
  595.         ActiveItem = NULL;
  596.         }
  597.     }
  598.     if (badItem != ActiveItem) badItem = NULL;
  599.     XFlush(dpy);
  600.     }
  601.  
  602. }
  603.  
  604.  
  605.  
  606. /***********************************************************************
  607.  *
  608.  *  Procedure:
  609.  *    NewMenuRoot - create a new menu root
  610.  *
  611.  *  Returned Value:
  612.  *    (MenuRoot *)
  613.  *
  614.  *  Inputs:
  615.  *    name    - the name of the menu root
  616.  *
  617.  ***********************************************************************
  618.  */
  619.  
  620. MenuRoot *
  621. NewMenuRoot(name)
  622.     char *name;
  623. {
  624.     MenuRoot *tmp;
  625.  
  626. #define UNUSED_PIXEL ((unsigned long) (~0))    /* more than 24 bits */
  627.  
  628.     tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
  629.     tmp->hi_fore = UNUSED_PIXEL;
  630.     tmp->hi_back = UNUSED_PIXEL;
  631.     tmp->name = name;
  632.     tmp->prev = NULL;
  633.     tmp->first = NULL;
  634.     tmp->last = NULL;
  635.     tmp->items = 0;
  636.     tmp->width = 0;
  637.     tmp->mapped = NEVER_MAPPED;
  638.     tmp->pull = FALSE;
  639.     tmp->w = None;
  640.     tmp->shadow = None;
  641.     tmp->real_menu = FALSE;
  642.  
  643.     if (Scr->MenuList == NULL)
  644.     {
  645.     Scr->MenuList = tmp;
  646.     Scr->MenuList->next = NULL;
  647.     }
  648.  
  649.     if (Scr->LastMenu == NULL)
  650.     {
  651.     Scr->LastMenu = tmp;
  652.     Scr->LastMenu->next = NULL;
  653.     }
  654.     else
  655.     {
  656.     Scr->LastMenu->next = tmp;
  657.     Scr->LastMenu = tmp;
  658.     Scr->LastMenu->next = NULL;
  659.     }
  660.  
  661.     if (strcmp(name, TWM_WINDOWS) == 0)
  662.     Scr->Windows = tmp;
  663.  
  664.     return (tmp);
  665. }
  666.  
  667.  
  668.  
  669. /***********************************************************************
  670.  *
  671.  *  Procedure:
  672.  *    AddToMenu - add an item to a root menu
  673.  *
  674.  *  Returned Value:
  675.  *    (MenuItem *)
  676.  *
  677.  *  Inputs:
  678.  *    menu    - pointer to the root menu to add the item
  679.  *    item    - the text to appear in the menu
  680.  *    action    - the string to possibly execute
  681.  *    sub    - the menu root if it is a pull-right entry
  682.  *    func    - the numeric function
  683.  *    fore    - foreground color string
  684.  *    back    - background color string
  685.  *
  686.  ***********************************************************************
  687.  */
  688.  
  689. MenuItem *
  690. AddToMenu(menu, item, action, sub, func, fore, back)
  691.     MenuRoot *menu;
  692.     char *item, *action;
  693.     MenuRoot *sub;
  694.     int func;
  695.     char *fore, *back;
  696. {
  697.     MenuItem *tmp;
  698.     int width;
  699.  
  700. #ifdef DEBUG_MENUS
  701.     fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
  702.     item, action, sub, func);
  703. #endif
  704.  
  705.     tmp = (MenuItem *) malloc(sizeof(MenuItem));
  706.     tmp->root = menu;
  707.  
  708.     if (menu->first == NULL)
  709.     {
  710.     menu->first = tmp;
  711.     tmp->prev = NULL;
  712.     }
  713.     else
  714.     {
  715.     menu->last->next = tmp;
  716.     tmp->prev = menu->last;
  717.     }
  718.     menu->last = tmp;
  719.  
  720.     tmp->item = item;
  721.     tmp->strlen = strlen(item);
  722.     tmp->action = action;
  723.     tmp->next = NULL;
  724.     tmp->sub = NULL;
  725.     tmp->state = 0;
  726.     tmp->func = func;
  727.  
  728.     if (!Scr->HaveFonts) CreateFonts();
  729.     width = XTextWidth(Scr->MenuFont.font, item, tmp->strlen);
  730.     if (width <= 0)
  731.     width = 1;
  732.     if (width > menu->width)
  733.     menu->width = width;
  734.  
  735.     tmp->user_colors = FALSE;
  736.     if (Scr->Monochrome == COLOR && fore != NULL)
  737.     {
  738.     int save;
  739.  
  740.     save = Scr->FirstTime;
  741.     Scr->FirstTime = TRUE;
  742.     GetColor(COLOR, &tmp->fore, fore);
  743.     GetColor(COLOR, &tmp->back, back);
  744.     Scr->FirstTime = save;
  745.     tmp->user_colors = TRUE;
  746.     }
  747.     if (sub != NULL)
  748.     {
  749.     tmp->sub = sub;
  750.     menu->pull = TRUE;
  751.     }
  752.     tmp->item_num = menu->items++;
  753.  
  754.     return (tmp);
  755. }
  756.  
  757.  
  758.  
  759. MakeMenus()
  760. {
  761.     MenuRoot *mr;
  762.  
  763.     for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
  764.     {
  765.     if (mr->real_menu == FALSE)
  766.         continue;
  767.  
  768.     MakeMenu(mr);
  769.     }
  770. }
  771.  
  772.  
  773.  
  774. MakeMenu(mr)
  775. MenuRoot *mr;
  776. {
  777.     MenuItem *start, *end, *cur, *tmp;
  778.     XColor f1, f2, f3;
  779.     XColor b1, b2, b3;
  780.     XColor save_fore, save_back;
  781.     int num, i;
  782.     int fred, fgreen, fblue;
  783.     int bred, bgreen, bblue;
  784.     int width;
  785.     unsigned long valuemask;
  786.     XSetWindowAttributes attributes;
  787.     Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
  788.  
  789.     Scr->EntryHeight = Scr->MenuFont.height + 4;
  790.  
  791.     /* lets first size the window accordingly */
  792.     if (mr->mapped == NEVER_MAPPED)
  793.     {
  794.     if (mr->pull == TRUE)
  795.     {
  796.         mr->width += 16 + 10;
  797.     }
  798.  
  799.     width = mr->width + 10;
  800.  
  801.     for (cur = mr->first; cur != NULL; cur = cur->next)
  802.     {
  803.         if (cur->func != F_TITLE)
  804.         cur->x = 5;
  805.         else
  806.         {
  807.         cur->x = width - XTextWidth(Scr->MenuFont.font, cur->item,
  808.             cur->strlen);
  809.         cur->x /= 2;
  810.         }
  811.     }
  812.     mr->height = mr->items * Scr->EntryHeight;
  813.     mr->width += 10;
  814.  
  815.     if (Scr->Shadow)
  816.     {
  817.         /*
  818.          * Make sure that you don't draw into the shadow window or else
  819.          * the background bits there will get saved
  820.          */
  821.         valuemask = (CWBackPixel | CWBorderPixel);
  822.         attributes.background_pixel = Scr->MenuShadowColor;
  823.         attributes.border_pixel = Scr->MenuShadowColor;
  824.         if (Scr->SaveUnder) {
  825.         valuemask |= CWSaveUnder;
  826.         attributes.save_under = True;
  827.         }
  828.         mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
  829.                     (unsigned int) mr->width, 
  830.                     (unsigned int) mr->height,
  831.                     (unsigned int)0,
  832.                     CopyFromParent, 
  833.                     (unsigned int) CopyFromParent,
  834.                     (Visual *) CopyFromParent,
  835.                     valuemask, &attributes);
  836.     }
  837.  
  838.     valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
  839.     attributes.background_pixel = Scr->MenuC.back;
  840.     attributes.border_pixel = Scr->MenuC.fore;
  841.     attributes.event_mask = (ExposureMask | EnterWindowMask);
  842.     if (Scr->SaveUnder) {
  843.         valuemask |= CWSaveUnder;
  844.         attributes.save_under = True;
  845.     }
  846.     if (Scr->BackingStore) {
  847.         valuemask |= CWBackingStore;
  848.         attributes.backing_store = Always;
  849.     }
  850.     mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
  851.                    (unsigned int) mr->height, (unsigned int) 1,
  852.                    CopyFromParent, (unsigned int) CopyFromParent,
  853.                    (Visual *) CopyFromParent,
  854.                    valuemask, &attributes);
  855.  
  856.  
  857.     XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
  858.     XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
  859.  
  860.     mr->mapped = UNMAPPED;
  861.     }
  862.  
  863.     /* get the default colors into the menus */
  864.     for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
  865.     {
  866.     if (!tmp->user_colors) {
  867.         if (tmp->func != F_TITLE) {
  868.         tmp->fore = Scr->MenuC.fore;
  869.         tmp->back = Scr->MenuC.back;
  870.         } else {
  871.         tmp->fore = Scr->MenuTitleC.fore;
  872.         tmp->back = Scr->MenuTitleC.back;
  873.         }
  874.     }
  875.  
  876.     if (mr->hi_fore != UNUSED_PIXEL)
  877.     {
  878.         tmp->hi_fore = mr->hi_fore;
  879.         tmp->hi_back = mr->hi_back;
  880.     }
  881.     else
  882.     {
  883.         tmp->hi_fore = tmp->back;
  884.         tmp->hi_back = tmp->fore;
  885.     }
  886.     }
  887.  
  888.     if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
  889.     return;
  890.  
  891.     start = mr->first;
  892.     while (TRUE)
  893.     {
  894.     for (; start != NULL; start = start->next)
  895.     {
  896.         if (start->user_colors)
  897.         break;
  898.     }
  899.     if (start == NULL)
  900.         break;
  901.  
  902.     for (end = start->next; end != NULL; end = end->next)
  903.     {
  904.         if (end->user_colors)
  905.         break;
  906.     }
  907.     if (end == NULL)
  908.         break;
  909.  
  910.     /* we have a start and end to interpolate between */
  911.     num = end->item_num - start->item_num;
  912.  
  913.     f1.pixel = start->fore;
  914.     XQueryColor(dpy, cmap, &f1);
  915.     f2.pixel = end->fore;
  916.     XQueryColor(dpy, cmap, &f2);
  917.  
  918.     b1.pixel = start->back;
  919.     XQueryColor(dpy, cmap, &b1);
  920.     b2.pixel = end->back;
  921.     XQueryColor(dpy, cmap, &b2);
  922.  
  923.     fred = ((int)f2.red - (int)f1.red) / num;
  924.     fgreen = ((int)f2.green - (int)f1.green) / num;
  925.     fblue = ((int)f2.blue - (int)f1.blue) / num;
  926.  
  927.     bred = ((int)b2.red - (int)b1.red) / num;
  928.     bgreen = ((int)b2.green - (int)b1.green) / num;
  929.     bblue = ((int)b2.blue - (int)b1.blue) / num;
  930.  
  931.     f3 = f1;
  932.     f3.flags = DoRed | DoGreen | DoBlue;
  933.  
  934.     b3 = b1;
  935.     b3.flags = DoRed | DoGreen | DoBlue;
  936.  
  937.     num -= 1;
  938.     for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
  939.     {
  940.         f3.red += fred;
  941.         f3.green += fgreen;
  942.         f3.blue += fblue;
  943.         save_fore = f3;
  944.  
  945.         b3.red += bred;
  946.         b3.green += bgreen;
  947.         b3.blue += bblue;
  948.         save_back = b3;
  949.  
  950.         XAllocColor(dpy, cmap, &f3);
  951.         XAllocColor(dpy, cmap, &b3);
  952.         cur->hi_back = cur->fore = f3.pixel;
  953.         cur->hi_fore = cur->back = b3.pixel;
  954.         cur->user_colors = True;
  955.  
  956.         f3 = save_fore;
  957.         b3 = save_back;
  958.     }
  959.     start = end;
  960.     }
  961. }
  962.  
  963.  
  964.  
  965. /***********************************************************************
  966.  *
  967.  *  Procedure:
  968.  *    PopUpMenu - pop up a pull down menu
  969.  *
  970.  *  Inputs:
  971.  *    menu    - the root pointer of the menu to pop up
  972.  *    x, y    - location of upper left of menu
  973.  *      center    - whether or not to center horizontally over position
  974.  *
  975.  ***********************************************************************
  976.  */
  977.  
  978. Bool PopUpMenu (menu, x, y, center)
  979.     MenuRoot *menu;
  980.     int x, y;
  981.     Bool center;
  982. {
  983.     int WindowNameOffset, WindowNameCount;
  984.     TwmWindow **WindowNames;
  985.     TwmWindow *tmp_win2,*tmp_win3;
  986.     int i;
  987.     int (*compar)() = 
  988.       (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
  989.  
  990.     if (!menu) return False;
  991.  
  992.     InstallRootColormap();
  993.  
  994.     if (menu == Scr->Windows)
  995.     {
  996.     TwmWindow *tmp_win;
  997.  
  998.     /* this is the twm windows menu,  let's go ahead and build it */
  999.  
  1000.     DestroyMenu (menu);
  1001.  
  1002.     menu->first = NULL;
  1003.     menu->last = NULL;
  1004.     menu->items = 0;
  1005.     menu->width = 0;
  1006.     menu->mapped = NEVER_MAPPED;
  1007.       AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
  1008.   
  1009.         WindowNameOffset=(char *)Scr->TwmRoot.next->name -
  1010.                                (char *)Scr->TwmRoot.next;
  1011.         for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
  1012.             tmp_win != NULL;
  1013.             tmp_win = tmp_win->next)
  1014.           WindowNameCount++;
  1015.         WindowNames =
  1016.           (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
  1017.         WindowNames[0] = Scr->TwmRoot.next;
  1018.         for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
  1019.             tmp_win != NULL;
  1020.             tmp_win = tmp_win->next,WindowNameCount++)
  1021.         {
  1022.             tmp_win2 = tmp_win;
  1023.             for (i=0;i<WindowNameCount;i++)
  1024.             {
  1025.                 if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
  1026.                 {
  1027.                     tmp_win3 = tmp_win2;
  1028.                     tmp_win2 = WindowNames[i];
  1029.                     WindowNames[i] = tmp_win3;
  1030.                 }
  1031.             }
  1032.             WindowNames[WindowNameCount] = tmp_win2;
  1033.         }
  1034.         for (i=0; i<WindowNameCount; i++)
  1035.         {
  1036.             AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
  1037.                       NULL, F_POPUP,NULL,NULL);
  1038.         }
  1039.         free(WindowNames);
  1040.  
  1041.     MakeMenu(menu);
  1042.     }
  1043.  
  1044.     if (menu->w == None || menu->items == 0) return False;
  1045.  
  1046.     /* Prevent recursively bringing up menus. */
  1047.     if (menu->mapped == MAPPED) return False;
  1048.  
  1049.     /*
  1050.      * Dynamically set the parent;  this allows pull-ups to also be main
  1051.      * menus, or to be brought up from more than one place.
  1052.      */
  1053.     menu->prev = ActiveMenu;
  1054.  
  1055.     XGrabPointer(dpy, Scr->Root, True,
  1056.     ButtonPressMask | ButtonReleaseMask |
  1057.     ButtonMotionMask | PointerMotionHintMask,
  1058.     GrabModeAsync, GrabModeAsync,
  1059.     Scr->Root, Scr->MenuCursor, CurrentTime);
  1060.  
  1061.     ActiveMenu = menu;
  1062.     menu->mapped = MAPPED;
  1063.     menu->entered = FALSE;
  1064.  
  1065.     if (center) {
  1066.     x -= (menu->width / 2);
  1067.     y -= (Scr->EntryHeight / 2);    /* sticky menus would be nice here */
  1068.     }
  1069.  
  1070.     /*
  1071.      * clip to screen
  1072.      */
  1073.     if (x + menu->width > Scr->MyDisplayWidth) {
  1074.     x = Scr->MyDisplayWidth - menu->width;
  1075.     }
  1076.     if (x < 0) x = 0;
  1077.     if (y + menu->height > Scr->MyDisplayHeight) {
  1078.     y = Scr->MyDisplayHeight - menu->height;
  1079.     }
  1080.     if (y < 0) y = 0;
  1081.  
  1082.     MenuOrigins[MenuDepth].x = x;
  1083.     MenuOrigins[MenuDepth].y = y;
  1084.     MenuDepth++;
  1085.  
  1086.     XMoveWindow(dpy, menu->w, x, y);
  1087.     if (Scr->Shadow) {
  1088.     XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
  1089.     }
  1090.     if (Scr->Shadow) {
  1091.     XRaiseWindow (dpy, menu->shadow);
  1092.     }
  1093.     XMapRaised(dpy, menu->w);
  1094.     if (Scr->Shadow) {
  1095.     XMapWindow (dpy, menu->shadow);
  1096.     }
  1097.     XSync(dpy, 0);
  1098.     return True;
  1099. }
  1100.  
  1101.  
  1102.  
  1103. /***********************************************************************
  1104.  *
  1105.  *  Procedure:
  1106.  *    PopDownMenu - unhighlight the current menu selection and
  1107.  *        take down the menus
  1108.  *
  1109.  ***********************************************************************
  1110.  */
  1111.  
  1112. PopDownMenu()
  1113. {
  1114.     MenuRoot *tmp;
  1115.  
  1116.     if (ActiveMenu == NULL)
  1117.     return;
  1118.  
  1119.     if (ActiveItem)
  1120.     {
  1121.     ActiveItem->state = 0;
  1122.     PaintEntry(ActiveMenu, ActiveItem, False);
  1123.     }
  1124.  
  1125.     for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
  1126.     {
  1127.     if (Scr->Shadow) {
  1128.         XUnmapWindow (dpy, tmp->shadow);
  1129.     }
  1130.     XUnmapWindow(dpy, tmp->w);
  1131.     tmp->mapped = UNMAPPED;
  1132.     UninstallRootColormap();
  1133.     }
  1134.  
  1135.     XFlush(dpy);
  1136.     ActiveMenu = NULL;
  1137.     ActiveItem = NULL;
  1138.     MenuDepth = 0;
  1139.     if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
  1140.       menuFromFrameOrWindowOrTitlebar = TRUE;
  1141. }
  1142.  
  1143.  
  1144.  
  1145. /***********************************************************************
  1146.  *
  1147.  *  Procedure:
  1148.  *    FindMenuRoot - look for a menu root
  1149.  *
  1150.  *  Returned Value:
  1151.  *    (MenuRoot *)  - a pointer to the menu root structure 
  1152.  *
  1153.  *  Inputs:
  1154.  *    name    - the name of the menu root 
  1155.  *
  1156.  ***********************************************************************
  1157.  */
  1158.  
  1159. MenuRoot *
  1160. FindMenuRoot(name)
  1161.     char *name;
  1162. {
  1163.     MenuRoot *tmp;
  1164.  
  1165.     for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
  1166.     {
  1167.     if (strcmp(name, tmp->name) == 0)
  1168.         return (tmp);
  1169.     }
  1170.     return NULL;
  1171. }
  1172.  
  1173.  
  1174.  
  1175. static Bool belongs_to_twm_window (t, w)
  1176.     register TwmWindow *t;
  1177.     register Window w;
  1178. {
  1179.     if (!t) return False;
  1180.  
  1181.     if (w == t->frame || w == t->title_w || w == t->hilite_w ||
  1182.     w == t->icon_w || w == t->icon_bm_w) return True;
  1183.     
  1184.     if (t && t->titlebuttons) {
  1185.     register TBWindow *tbw;
  1186.     register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1187.     for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
  1188.         if (tbw->window == w) return True;
  1189.     }
  1190.     }
  1191.     return False;
  1192. }
  1193.  
  1194.  
  1195.  
  1196.  
  1197. /***********************************************************************
  1198.  *
  1199.  *  Procedure:
  1200.  *    resizeFromCenter -
  1201.  *
  1202.  ***********************************************************************
  1203.  */
  1204.  
  1205.  
  1206. extern int AddingX;
  1207. extern int AddingY;
  1208. extern int AddingW;
  1209. extern int AddingH;
  1210.  
  1211. void resizeFromCenter(w, tmp_win)
  1212.      Window w;
  1213.      TwmWindow *tmp_win;
  1214. {
  1215.   int lastx, lasty, width, height, bw2;
  1216.   int namelen;
  1217.   int stat;
  1218.   XEvent event;
  1219.   Window junk;
  1220.  
  1221.   namelen = strlen (tmp_win->name);
  1222.   bw2 = tmp_win->frame_bw * 2;
  1223.   AddingW = tmp_win->attr.width + bw2;
  1224.   AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
  1225.   width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
  1226.                       tmp_win->name, namelen));
  1227.   height = Scr->SizeFont.height + SIZE_VINDENT * 2;
  1228.   XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
  1229.            (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, 
  1230.            &JunkBW, &JunkDepth);
  1231.   XWarpPointer(dpy, None, w,
  1232.            0, 0, 0, 0, DragWidth/2, DragHeight/2);   
  1233.   XQueryPointer (dpy, Scr->Root, &JunkRoot, 
  1234.          &JunkChild, &JunkX, &JunkY,
  1235.          &AddingX, &AddingY, &JunkMask);
  1236. /*****
  1237.   Scr->SizeStringOffset = width +
  1238.     XTextWidth(Scr->SizeFont.font, ": ", 2);
  1239.   XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
  1240.          Scr->SizeStringWidth, height);
  1241.   XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
  1242.             SIZE_VINDENT + Scr->SizeFont.font->ascent,
  1243.             ": ", 2);
  1244. *****/
  1245.   lastx = -10000;
  1246.   lasty = -10000;
  1247. /*****
  1248.   MoveOutline(Scr->Root,
  1249.           origDragX - JunkBW, origDragY - JunkBW,
  1250.           DragWidth * JunkBW, DragHeight * JunkBW,
  1251.           tmp_win->frame_bw,
  1252.           tmp_win->title_height);
  1253. *****/
  1254.   MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
  1255.   while (TRUE)
  1256.     {
  1257.       XMaskEvent(dpy,
  1258.          ButtonPressMask | PointerMotionMask, &event);
  1259.       
  1260.       if (event.type == MotionNotify) {
  1261.     /* discard any extra motion events before a release */
  1262.     while(XCheckMaskEvent(dpy,
  1263.                   ButtonMotionMask | ButtonPressMask, &event))
  1264.       if (event.type == ButtonPress)
  1265.         break;
  1266.       }
  1267.       
  1268.       if (event.type == ButtonPress)
  1269.     {
  1270.       MenuEndResize(tmp_win);
  1271.       XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
  1272.       break;
  1273.     }
  1274.       
  1275. /*    if (!DispatchEvent ()) continue; */
  1276.  
  1277.       if (event.type != MotionNotify) {
  1278.     continue;
  1279.       }
  1280.       
  1281.       /*
  1282.        * XXX - if we are going to do a loop, we ought to consider
  1283.        * using multiple GXxor lines so that we don't need to 
  1284.        * grab the server.
  1285.        */
  1286.       XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
  1287.             &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
  1288.       
  1289.       if (lastx != AddingX || lasty != AddingY)
  1290.     {
  1291.       MenuDoResize(AddingX, AddingY, tmp_win);
  1292.       
  1293.       lastx = AddingX;
  1294.       lasty = AddingY;
  1295.     }
  1296.       
  1297.     }
  1298.  
  1299.  
  1300.  
  1301. /***********************************************************************
  1302.  *
  1303.  *  Procedure:
  1304.  *    ExecuteFunction - execute a twm root function
  1305.  *
  1306.  *  Inputs:
  1307.  *    func    - the function to execute
  1308.  *    action    - the menu action to execute 
  1309.  *    w    - the window to execute this function on
  1310.  *    tmp_win    - the twm window structure
  1311.  *    event    - the event that caused the function
  1312.  *    context - the context in which the button was pressed
  1313.  *    pulldown- flag indicating execution from pull down menu
  1314.  *
  1315.  *  Returns:
  1316.  *    TRUE if should continue with remaining actions else FALSE to abort
  1317.  *
  1318.  ***********************************************************************
  1319.  */
  1320.  
  1321. int
  1322. ExecuteFunction(func, action, w, tmp_win, eventp, context, pulldown)
  1323.     int func;
  1324.     char *action;
  1325.     Window w;
  1326.     TwmWindow *tmp_win;
  1327.     XEvent *eventp;
  1328.     int context;
  1329.     int pulldown;
  1330. {
  1331.     static Time last_time = 0;
  1332.     char tmp[200];
  1333.     char *ptr;
  1334.     char buff[MAX_FILE_SIZE];
  1335.     int count, fd;
  1336.     Window rootw;
  1337.     int origX, origY;
  1338.     int do_next_action = TRUE;
  1339.     int moving_icon = FALSE;
  1340.     Bool fromtitlebar = False;
  1341.     extern int ConstrainedMoveTime;
  1342.  
  1343.     RootFunction = NULL;
  1344.     if (Cancel)
  1345.     return TRUE;            /* XXX should this be FALSE? */
  1346.  
  1347.     switch (func)
  1348.     {
  1349.     case F_UPICONMGR:
  1350.     case F_LEFTICONMGR:
  1351.     case F_RIGHTICONMGR:
  1352.     case F_DOWNICONMGR:
  1353.     case F_FORWICONMGR:
  1354.     case F_BACKICONMGR:
  1355.     case F_NEXTICONMGR:
  1356.     case F_PREVICONMGR:
  1357.     case F_NOP:
  1358.     case F_TITLE:
  1359.     case F_DELTASTOP:
  1360.     case F_RAISELOWER:
  1361.     case F_WARPTOSCREEN:
  1362.     case F_WARPTO:
  1363.     case F_WARPRING:
  1364.     case F_WARPTOICONMGR:
  1365.     case F_COLORMAP:
  1366.     break;
  1367.     default:
  1368.         XGrabPointer(dpy, Scr->Root, True,
  1369.             ButtonPressMask | ButtonReleaseMask,
  1370.             GrabModeAsync, GrabModeAsync,
  1371.             Scr->Root, Scr->WaitCursor, CurrentTime);
  1372.     break;
  1373.     }
  1374.  
  1375.     switch (func)
  1376.     {
  1377.     case F_NOP:
  1378.     case F_TITLE:
  1379.     break;
  1380.  
  1381.     case F_DELTASTOP:
  1382.     if (WindowMoved) do_next_action = FALSE;
  1383.     break;
  1384.  
  1385.     case F_RESTART:
  1386.     XSync (dpy, 0);
  1387.     Reborder (eventp->xbutton.time);
  1388.     XSync (dpy, 0);
  1389.     execvp(*Argv, Argv);
  1390.     fprintf (stderr, "%s:  unable to restart:  %s\n", ProgramName, *Argv);
  1391.     break;
  1392.  
  1393.     case F_UPICONMGR:
  1394.     case F_DOWNICONMGR:
  1395.     case F_LEFTICONMGR:
  1396.     case F_RIGHTICONMGR:
  1397.     case F_FORWICONMGR:
  1398.     case F_BACKICONMGR:
  1399.     MoveIconManager(func);
  1400.         break;
  1401.  
  1402.     case F_NEXTICONMGR:
  1403.     case F_PREVICONMGR:
  1404.     JumpIconManager(func);
  1405.         break;
  1406.  
  1407.     case F_SHOWLIST:
  1408.     if (Scr->NoIconManagers)
  1409.         break;
  1410.     DeIconify(Scr->iconmgr.twm_win);
  1411.     XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame);
  1412.     break;
  1413.  
  1414.     case F_HIDELIST:
  1415.     if (Scr->NoIconManagers)
  1416.         break;
  1417.     HideIconManager ();
  1418.     break;
  1419.  
  1420.     case F_SORTICONMGR:
  1421.     if (DeferExecution(context, func, Scr->SelectCursor))
  1422.         return TRUE;
  1423.  
  1424.     {
  1425.         int save_sort;
  1426.  
  1427.         save_sort = Scr->SortIconMgr;
  1428.         Scr->SortIconMgr = TRUE;
  1429.  
  1430.         if (context == C_ICONMGR)
  1431.         SortIconManager((IconMgr *) NULL);
  1432.         else if (tmp_win->iconmgr)
  1433.         SortIconManager(tmp_win->iconmgrp);
  1434.         else
  1435.         XBell(dpy, 0);
  1436.  
  1437.         Scr->SortIconMgr = save_sort;
  1438.     }
  1439.     break;
  1440.  
  1441.     case F_IDENTIFY:
  1442.     if (DeferExecution(context, func, Scr->SelectCursor))
  1443.         return TRUE;
  1444.  
  1445.     Identify(tmp_win);
  1446.     break;
  1447.  
  1448.     case F_VERSION:
  1449.     Identify ((TwmWindow *) NULL);
  1450.     break;
  1451.  
  1452.     case F_AUTORAISE:
  1453.     if (DeferExecution(context, func, Scr->SelectCursor))
  1454.         return TRUE;
  1455.  
  1456.     tmp_win->auto_raise = !tmp_win->auto_raise;
  1457.     if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
  1458.     else --(Scr->NumAutoRaises);
  1459.     break;
  1460.  
  1461.     case F_BEEP:
  1462.     XBell(dpy, 0);
  1463.     break;
  1464.  
  1465.     case F_POPUP:
  1466.     tmp_win = (TwmWindow *)action;
  1467.     if (Scr->WindowFunction.func != NULL)
  1468.     {
  1469.        ExecuteFunction(Scr->WindowFunction.func,
  1470.                Scr->WindowFunction.item->action,
  1471.                w, tmp_win, eventp, C_FRAME, FALSE);
  1472.     }
  1473.     else
  1474.     {
  1475.         DeIconify(tmp_win);
  1476.         XRaiseWindow (dpy, tmp_win->frame);
  1477.     }
  1478.     break;
  1479.  
  1480.     case F_RESIZE:
  1481.     EventHandler[EnterNotify] = HandleUnknown;
  1482.     EventHandler[LeaveNotify] = HandleUnknown;
  1483.     if (DeferExecution(context, func, Scr->MoveCursor))
  1484.         return TRUE;
  1485.  
  1486.     PopDownMenu();
  1487.  
  1488.     if (pulldown)
  1489.         XWarpPointer(dpy, None, Scr->Root, 
  1490.         0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
  1491.  
  1492.     if (w != tmp_win->icon_w) {    /* can't resize icons */
  1493.  
  1494.       if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
  1495.           && fromMenu) 
  1496.         resizeFromCenter(w, tmp_win);
  1497.       else {
  1498.         /*
  1499.          * see if this is being done from the titlebar
  1500.          */
  1501.         fromtitlebar = 
  1502.           belongs_to_twm_window (tmp_win, eventp->xbutton.window);
  1503.         
  1504.         /* Save pointer position so we can tell if it was moved or
  1505.            not during the resize. */
  1506.         ResizeOrigX = eventp->xbutton.x_root;
  1507.         ResizeOrigY = eventp->xbutton.y_root;
  1508.         
  1509.         StartResize (eventp, tmp_win, fromtitlebar);
  1510.         
  1511.         do {
  1512.           XMaskEvent(dpy,
  1513.                ButtonPressMask | ButtonReleaseMask |
  1514.                EnterWindowMask | LeaveWindowMask |
  1515.                ButtonMotionMask, &Event);
  1516.         
  1517.         if (fromtitlebar && Event.type == ButtonPress) {
  1518.           fromtitlebar = False;
  1519.             continue;
  1520.           }
  1521.         
  1522.             if (Event.type == MotionNotify) {
  1523.           /* discard any extra motion events before a release */
  1524.           while
  1525.             (XCheckMaskEvent
  1526.              (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
  1527.               if (Event.type == ButtonRelease)
  1528.             break;
  1529.         }
  1530.           
  1531.           if (!DispatchEvent ()) continue;
  1532.           
  1533.         } while (!(Event.type == ButtonRelease || Cancel));
  1534.         return TRUE;
  1535.       }
  1536.     } 
  1537.     break;
  1538.  
  1539.  
  1540.     case F_ZOOM:
  1541.     case F_HORIZOOM:
  1542.     case F_FULLZOOM:
  1543.     case F_LEFTZOOM:
  1544.     case F_RIGHTZOOM:
  1545.     case F_TOPZOOM:
  1546.     case F_BOTTOMZOOM:
  1547.     if (DeferExecution(context, func, Scr->SelectCursor))
  1548.         return TRUE;
  1549.     fullzoom(tmp_win, func);
  1550.     break;
  1551.  
  1552.     case F_MOVE:
  1553.     case F_FORCEMOVE:
  1554.     if (DeferExecution(context, func, Scr->MoveCursor))
  1555.         return TRUE;
  1556.  
  1557.     PopDownMenu();
  1558.     rootw = eventp->xbutton.root;
  1559.     MoveFunction = func;
  1560.  
  1561.     if (pulldown)
  1562.         XWarpPointer(dpy, None, Scr->Root, 
  1563.         0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
  1564.  
  1565.     EventHandler[EnterNotify] = HandleUnknown;
  1566.     EventHandler[LeaveNotify] = HandleUnknown;
  1567.  
  1568.     if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
  1569.         XGrabServer(dpy);
  1570.     }
  1571.     XGrabPointer(dpy, eventp->xbutton.root, True,
  1572.         ButtonPressMask | ButtonReleaseMask |
  1573.         ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
  1574.         GrabModeAsync, GrabModeAsync,
  1575.         Scr->Root, Scr->MoveCursor, CurrentTime);
  1576.  
  1577.     if (context == C_ICON && tmp_win->icon_w)
  1578.     {
  1579.         w = tmp_win->icon_w;
  1580.         DragX = eventp->xbutton.x;
  1581.         DragY = eventp->xbutton.y;
  1582.         moving_icon = TRUE;
  1583.     }
  1584.  
  1585.     else if (w != tmp_win->icon_w)
  1586.     {
  1587.         XTranslateCoordinates(dpy, w, tmp_win->frame,
  1588.         eventp->xbutton.x, 
  1589.         eventp->xbutton.y, 
  1590.         &DragX, &DragY, &JunkChild);
  1591.  
  1592.         w = tmp_win->frame;
  1593.     }
  1594.  
  1595.     DragWindow = None;
  1596.  
  1597.     XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
  1598.         (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
  1599.         &JunkDepth);
  1600.  
  1601.     origX = eventp->xbutton.x_root;
  1602.     origY = eventp->xbutton.y_root;
  1603.     CurrentDragX = origDragX;
  1604.     CurrentDragY = origDragY;
  1605.  
  1606.     /*
  1607.      * only do the constrained move if timer is set; need to check it
  1608.      * in case of stupid or wicked fast servers
  1609.      */
  1610.     if (ConstrainedMoveTime && 
  1611.         (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
  1612.     {
  1613.         int width, height;
  1614.  
  1615.         ConstMove = TRUE;
  1616.         ConstMoveDir = MOVE_NONE;
  1617.         ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
  1618.         ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
  1619.         width = DragWidth + 2 * JunkBW;
  1620.         height = DragHeight + 2 * JunkBW;
  1621.         ConstMoveXL = ConstMoveX + width/3;
  1622.         ConstMoveXR = ConstMoveX + 2*(width/3);
  1623.         ConstMoveYT = ConstMoveY + height/3;
  1624.         ConstMoveYB = ConstMoveY + 2*(height/3);
  1625.  
  1626.         XWarpPointer(dpy, None, w,
  1627.         0, 0, 0, 0, DragWidth/2, DragHeight/2);
  1628.  
  1629.         XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
  1630.         &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
  1631.     }
  1632.     last_time = eventp->xbutton.time;
  1633.  
  1634.     if (!Scr->OpaqueMove)
  1635.     {
  1636.         InstallRootColormap();
  1637.         if (!Scr->MoveDelta)
  1638.         {
  1639.         /*
  1640.          * Draw initial outline.  This was previously done the
  1641.          * first time though the outer loop by dropping out of
  1642.          * the XCheckMaskEvent inner loop down to one of the
  1643.          * MoveOutline's below.
  1644.          */
  1645.         MoveOutline(rootw,
  1646.             origDragX - JunkBW, origDragY - JunkBW,
  1647.             DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
  1648.             tmp_win->frame_bw,
  1649.             moving_icon ? 0 : tmp_win->title_height);
  1650.         /*
  1651.          * This next line causes HandleReleaseNotify to call
  1652.          * XRaiseWindow().  This is solely to preserve the
  1653.          * previous behaviour that raises a window being moved
  1654.          * on button release even if you never actually moved
  1655.          * any distance (unless you move less than MoveDelta or
  1656.          * NoRaiseMove is set or OpaqueMove is set).
  1657.          */
  1658.         DragWindow = w;
  1659.         }
  1660.     }
  1661.  
  1662.     /*
  1663.      * see if this is being done from the titlebar
  1664.      */
  1665.     fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
  1666.  
  1667.     if (menuFromFrameOrWindowOrTitlebar) {
  1668.       /* warp the pointer to the middle of the window */
  1669.       XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, 
  1670.                origDragX + DragWidth / 2, 
  1671.                origDragY + DragHeight / 2);
  1672.       XFlush(dpy);
  1673.     }
  1674.     
  1675.     while (TRUE)
  1676.     {
  1677.         long releaseEvent = menuFromFrameOrWindowOrTitlebar ? 
  1678.                               ButtonPress : ButtonRelease;
  1679.         long movementMask = menuFromFrameOrWindowOrTitlebar ?
  1680.                               PointerMotionMask : ButtonMotionMask;
  1681.  
  1682.         /* block until there is an interesting event */
  1683.         XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
  1684.                     EnterWindowMask | LeaveWindowMask |
  1685.                     ExposureMask | movementMask |
  1686.                     VisibilityChangeMask, &Event);
  1687.  
  1688.         /* throw away enter and leave events until release */
  1689.         if (Event.xany.type == EnterNotify ||
  1690.         Event.xany.type == LeaveNotify) continue; 
  1691.  
  1692.         if (Event.type == MotionNotify) {
  1693.         /* discard any extra motion events before a logical release */
  1694.         while(XCheckMaskEvent(dpy,
  1695.             movementMask | releaseEvent, &Event))
  1696.             if (Event.type == releaseEvent)
  1697.             break;
  1698.         }
  1699.  
  1700.         /* test to see if we have a second button press to abort move */
  1701.         if (!menuFromFrameOrWindowOrTitlebar)
  1702.           if (Event.type == ButtonPress && DragWindow != None) {
  1703.         if (Scr->OpaqueMove)
  1704.           XMoveWindow (dpy, DragWindow, origDragX, origDragY);
  1705.         else
  1706.           MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  1707.         DragWindow = None;
  1708.           }
  1709.  
  1710.         if (fromtitlebar && Event.type == ButtonPress) {
  1711.         fromtitlebar = False;
  1712.         CurrentDragX = origX = Event.xbutton.x_root;
  1713.         CurrentDragY = origY = Event.xbutton.y_root;
  1714.         XTranslateCoordinates (dpy, rootw, tmp_win->frame,
  1715.                        origX, origY,
  1716.                        &DragX, &DragY, &JunkChild);
  1717.         continue;
  1718.         }
  1719.  
  1720.         if (!DispatchEvent2 ()) continue;
  1721.  
  1722.         if (Cancel)
  1723.         {
  1724.         WindowMoved = FALSE;
  1725.         if (!Scr->OpaqueMove)
  1726.             UninstallRootColormap();
  1727.             return TRUE;    /* XXX should this be FALSE? */
  1728.         }
  1729.         if (Event.type == releaseEvent)
  1730.         {
  1731.         MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
  1732.         if (moving_icon &&
  1733.             ((CurrentDragX != origDragX ||
  1734.               CurrentDragY != origDragY)))
  1735.           tmp_win->icon_moved = TRUE;
  1736.         if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
  1737.           XMoveWindow(dpy, DragWindow, 
  1738.                   Event.xbutton.x_root - DragWidth / 2,
  1739.                   Event.xbutton.y_root - DragHeight / 2);
  1740.         break;
  1741.         }
  1742.  
  1743.         /* something left to do only if the pointer moved */
  1744.         if (Event.type != MotionNotify)
  1745.         continue;
  1746.  
  1747.         XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
  1748.         &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
  1749.         &JunkX, &JunkY, &JunkMask);
  1750.  
  1751.         if (DragWindow == None &&
  1752.         abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
  1753.             abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
  1754.         continue;
  1755.  
  1756.         WindowMoved = TRUE;
  1757.         DragWindow = w;
  1758.  
  1759.         if (!Scr->NoRaiseMove && Scr->OpaqueMove)    /* can't restore... */
  1760.           XRaiseWindow(dpy, DragWindow);
  1761.  
  1762.         if (ConstMove)
  1763.         {
  1764.         switch (ConstMoveDir)
  1765.         {
  1766.             case MOVE_NONE:
  1767.             if (eventp->xmotion.x_root < ConstMoveXL ||
  1768.                 eventp->xmotion.x_root > ConstMoveXR)
  1769.                 ConstMoveDir = MOVE_HORIZ;
  1770.  
  1771.             if (eventp->xmotion.y_root < ConstMoveYT ||
  1772.                 eventp->xmotion.y_root > ConstMoveYB)
  1773.                 ConstMoveDir = MOVE_VERT;
  1774.  
  1775.             XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
  1776.                 &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
  1777.             break;
  1778.  
  1779.             case MOVE_VERT:
  1780.             ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
  1781.             break;
  1782.  
  1783.             case MOVE_HORIZ:
  1784.             ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
  1785.             break;
  1786.         }
  1787.  
  1788.         if (ConstMoveDir != MOVE_NONE)
  1789.         {
  1790.             int xl, yt, xr, yb, w, h;
  1791.  
  1792.             xl = ConstMoveX;
  1793.             yt = ConstMoveY;
  1794.             w = DragWidth + 2 * JunkBW;
  1795.             h = DragHeight + 2 * JunkBW;
  1796.  
  1797.             if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
  1798.             {
  1799.             xr = xl + w;
  1800.             yb = yt + h;
  1801.  
  1802.             if (xl < 0)
  1803.                 xl = 0;
  1804.             if (xr > Scr->MyDisplayWidth)
  1805.                 xl = Scr->MyDisplayWidth - w;
  1806.  
  1807.             if (yt < 0)
  1808.                 yt = 0;
  1809.             if (yb > Scr->MyDisplayHeight)
  1810.                 yt = Scr->MyDisplayHeight - h;
  1811.             }
  1812.             CurrentDragX = xl;
  1813.             CurrentDragY = yt;
  1814.             if (Scr->OpaqueMove)
  1815.             XMoveWindow(dpy, DragWindow, xl, yt);
  1816.             else
  1817.             MoveOutline(eventp->xmotion.root, xl, yt, w, h,
  1818.                 tmp_win->frame_bw, 
  1819.                 moving_icon ? 0 : tmp_win->title_height);
  1820.         }
  1821.         }
  1822.         else if (DragWindow != None)
  1823.         {
  1824.         int xl, yt, xr, yb, w, h;
  1825.         if (!menuFromFrameOrWindowOrTitlebar) {
  1826.           xl = eventp->xmotion.x_root - DragX - JunkBW;
  1827.           yt = eventp->xmotion.y_root - DragY - JunkBW;
  1828.         }
  1829.         else {
  1830.           xl = eventp->xmotion.x_root - (DragWidth / 2);
  1831.           yt = eventp->xmotion.y_root - (DragHeight / 2);
  1832.         }          
  1833.         w = DragWidth + 2 * JunkBW;
  1834.         h = DragHeight + 2 * JunkBW;
  1835.  
  1836.         if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
  1837.         {
  1838.             xr = xl + w;
  1839.             yb = yt + h;
  1840.  
  1841.             if (xl < 0)
  1842.             xl = 0;
  1843.             if (xr > Scr->MyDisplayWidth)
  1844.             xl = Scr->MyDisplayWidth - w;
  1845.  
  1846.             if (yt < 0)
  1847.             yt = 0;
  1848.             if (yb > Scr->MyDisplayHeight)
  1849.             yt = Scr->MyDisplayHeight - h;
  1850.         }
  1851.  
  1852.         CurrentDragX = xl;
  1853.         CurrentDragY = yt;
  1854.         if (Scr->OpaqueMove)
  1855.             XMoveWindow(dpy, DragWindow, xl, yt);
  1856.         else
  1857.             MoveOutline(eventp->xmotion.root, xl, yt, w, h,
  1858.             tmp_win->frame_bw,
  1859.             moving_icon ? 0 : tmp_win->title_height);
  1860.         }
  1861.  
  1862.     }
  1863.  
  1864.     if (!Scr->OpaqueMove && DragWindow == None)
  1865.         UninstallRootColormap();
  1866.  
  1867.         break;
  1868.  
  1869.     case F_FUNCTION:
  1870.     {
  1871.         MenuRoot *mroot;
  1872.         MenuItem *mitem;
  1873.  
  1874.         if ((mroot = FindMenuRoot(action)) == NULL)
  1875.         {
  1876.         fprintf (stderr, "%s: couldn't find function \"%s\"\n", 
  1877.              ProgramName, action);
  1878.         return TRUE;
  1879.         }
  1880.  
  1881.         if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
  1882.         return TRUE;
  1883.         else
  1884.         {
  1885.         for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
  1886.         {
  1887.             if (!ExecuteFunction (mitem->func, mitem->action, w,
  1888.                       tmp_win, eventp, context, pulldown))
  1889.               break;
  1890.         }
  1891.         }
  1892.     }
  1893.     break;
  1894.  
  1895.     case F_DEICONIFY:
  1896.     case F_ICONIFY:
  1897.     if (DeferExecution(context, func, Scr->SelectCursor))
  1898.         return TRUE;
  1899.  
  1900.     if (tmp_win->icon)
  1901.     {
  1902.         DeIconify(tmp_win);
  1903.     }
  1904.         else if (func == F_ICONIFY)
  1905.     {
  1906.         Iconify (tmp_win, eventp->xbutton.x_root - 5,
  1907.              eventp->xbutton.y_root - 5);
  1908.     }
  1909.     break;
  1910.  
  1911.     case F_RAISELOWER:
  1912.     if (DeferExecution(context, func, Scr->SelectCursor))
  1913.         return TRUE;
  1914.  
  1915.     if (!WindowMoved) {
  1916.         XWindowChanges xwc;
  1917.  
  1918.         xwc.stack_mode = Opposite;
  1919.         if (w != tmp_win->icon_w)
  1920.           w = tmp_win->frame;
  1921.         XConfigureWindow (dpy, w, CWStackMode, &xwc);
  1922.     }
  1923.     break;
  1924.     
  1925.     case F_RAISE:
  1926.     if (DeferExecution(context, func, Scr->SelectCursor))
  1927.         return TRUE;
  1928.  
  1929.     /* check to make sure raise is not from the WindowFunction */
  1930.     if (w == tmp_win->icon_w && Context != C_ROOT) 
  1931.         XRaiseWindow(dpy, tmp_win->icon_w);
  1932.     else
  1933.         XRaiseWindow(dpy, tmp_win->frame);
  1934.  
  1935.     break;
  1936.  
  1937.     case F_LOWER:
  1938.     if (DeferExecution(context, func, Scr->SelectCursor))
  1939.         return TRUE;
  1940.  
  1941.     if (w == tmp_win->icon_w)
  1942.         XLowerWindow(dpy, tmp_win->icon_w);
  1943.     else
  1944.         XLowerWindow(dpy, tmp_win->frame);
  1945.  
  1946.     break;
  1947.  
  1948.     case F_FOCUS:
  1949.     if (DeferExecution(context, func, Scr->SelectCursor))
  1950.         return TRUE;
  1951.  
  1952.     if (tmp_win->icon == FALSE)
  1953.     {
  1954.         if (!Scr->FocusRoot && Scr->Focus == tmp_win)
  1955.         {
  1956.         FocusOnRoot();
  1957.         }
  1958.         else
  1959.         {
  1960.         if (Scr->Focus != NULL) {
  1961.             SetBorder (Scr->Focus, False);
  1962.             if (Scr->Focus->hilite_w)
  1963.               XUnmapWindow (dpy, Scr->Focus->hilite_w);
  1964.         }
  1965.  
  1966.         InstallWindowColormaps (0, tmp_win);
  1967.         if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
  1968.         SetBorder (tmp_win, True);
  1969.         SetFocus (tmp_win, eventp->xbutton.time);
  1970.         Scr->FocusRoot = FALSE;
  1971.         Scr->Focus = tmp_win;
  1972.         }
  1973.     }
  1974.     break;
  1975.  
  1976.     case F_DESTROY:
  1977.     if (DeferExecution(context, func, Scr->DestroyCursor))
  1978.         return TRUE;
  1979.  
  1980.     if (tmp_win->iconmgr)
  1981.         XBell(dpy, 0);
  1982.     else
  1983.         XKillClient(dpy, tmp_win->w);
  1984.     break;
  1985.  
  1986.     case F_DELETE:
  1987.     if (DeferExecution(context, func, Scr->DestroyCursor))
  1988.         return TRUE;
  1989.  
  1990.     if (tmp_win->iconmgr)        /* don't send ourself a message */
  1991.       HideIconManager ();
  1992.     else if (tmp_win->protocols & DoesWmDeleteWindow)
  1993.       SendDeleteWindowMessage (tmp_win, LastTimestamp());
  1994.     else
  1995.       XBell (dpy, 0);
  1996.     break;
  1997.  
  1998.     case F_SAVEYOURSELF:
  1999.     if (DeferExecution (context, func, Scr->SelectCursor))
  2000.       return TRUE;
  2001.  
  2002.     if (tmp_win->protocols & DoesWmSaveYourself)
  2003.       SendSaveYourselfMessage (tmp_win, LastTimestamp());
  2004.     else
  2005.       XBell (dpy, 0);
  2006.     break;
  2007.  
  2008.     case F_CIRCLEUP:
  2009.     XCirculateSubwindowsUp(dpy, Scr->Root);
  2010.     break;
  2011.  
  2012.     case F_CIRCLEDOWN:
  2013.     XCirculateSubwindowsDown(dpy, Scr->Root);
  2014.     break;
  2015.  
  2016.     case F_EXEC:
  2017.     PopDownMenu();
  2018.     if (!Scr->NoGrabServer) {
  2019.         XUngrabServer (dpy);
  2020.         XSync (dpy, 0);
  2021.     }
  2022.     Execute(action);
  2023.     break;
  2024.  
  2025.     case F_UNFOCUS:
  2026.     FocusOnRoot();
  2027.     break;
  2028.  
  2029.     case F_CUT:
  2030.     strcpy(tmp, action);
  2031.     strcat(tmp, "\n");
  2032.     XStoreBytes(dpy, tmp, strlen(tmp));
  2033.     break;
  2034.  
  2035.     case F_CUTFILE:
  2036.     ptr = XFetchBytes(dpy, &count);
  2037.     if (ptr) {
  2038.         if (sscanf (ptr, "%s", tmp) == 1) {
  2039.         XFree (ptr);
  2040.         ptr = ExpandFilename(tmp);
  2041.         if (ptr) {
  2042.             fd = open (ptr, 0);
  2043.             if (fd >= 0) {
  2044.             count = read (fd, buff, MAX_FILE_SIZE - 1);
  2045.             if (count > 0) XStoreBytes (dpy, buff, count);
  2046.             close(fd);
  2047.             } else {
  2048.             fprintf (stderr, 
  2049.                  "%s:  unable to open cut file \"%s\"\n", 
  2050.                  ProgramName, tmp);
  2051.             }
  2052.             if (ptr != tmp) free (ptr);
  2053.         } 
  2054.         } else {
  2055.         XFree(ptr);
  2056.         }
  2057.     } else {
  2058.         fprintf(stderr, "%s:  cut buffer is empty\n", ProgramName);
  2059.     }
  2060.     break;
  2061.  
  2062.     case F_WARPTOSCREEN:
  2063.     {
  2064.         if (strcmp (action, WARPSCREEN_NEXT) == 0) {
  2065.         WarpToScreen (Scr->screen + 1, 1);
  2066.         } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
  2067.         WarpToScreen (Scr->screen - 1, -1);
  2068.         } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
  2069.         WarpToScreen (PreviousScreen, 0);
  2070.         } else {
  2071.         WarpToScreen (atoi (action), 0);
  2072.         }
  2073.     }
  2074.     break;
  2075.  
  2076.     case F_COLORMAP:
  2077.     {
  2078.         if (strcmp (action, COLORMAP_NEXT) == 0) {
  2079.         BumpWindowColormap (tmp_win, 1);
  2080.         } else if (strcmp (action, COLORMAP_PREV) == 0) {
  2081.         BumpWindowColormap (tmp_win, -1);
  2082.         } else {
  2083.         BumpWindowColormap (tmp_win, 0);
  2084.         }
  2085.     }
  2086.     break;
  2087.  
  2088.     case F_WARPTO:
  2089.     {
  2090.         register TwmWindow *t;
  2091.         int len;
  2092.  
  2093.         len = strlen(action);
  2094.  
  2095.         for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
  2096.         if (!strncmp(action, t->class.res_name, len)) break;
  2097.         }
  2098.         if (!t) {
  2099.         for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
  2100.             if (!strncmp(action, t->class.res_name, len)) break;
  2101.         }
  2102.         if (!t) {
  2103.             for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
  2104.             if (!strncmp(action, t->class.res_class, len)) break;
  2105.             }
  2106.         }
  2107.         }
  2108.  
  2109.         if (t) {
  2110.         if (Scr->WarpUnmapped || t->mapped) {
  2111.             if (!t->mapped) DeIconify (t);
  2112.             if (!Scr->NoRaiseWarp) XRaiseWindow (dpy, t->frame);
  2113.             WarpToWindow (t);
  2114.         }
  2115.         } else {
  2116.         XBell (dpy, 0);
  2117.         }
  2118.     }
  2119.     break;
  2120.  
  2121.     case F_WARPTOICONMGR:
  2122.     {
  2123.         TwmWindow *t;
  2124.         int len;
  2125.         Window raisewin = None, iconwin = None;
  2126.  
  2127.         len = strlen(action);
  2128.         if (len == 0) {
  2129.         if (tmp_win && tmp_win->list) {
  2130.             raisewin = tmp_win->list->iconmgr->twm_win->frame;
  2131.             iconwin = tmp_win->list->icon;
  2132.         } else if (Scr->iconmgr.active) {
  2133.             raisewin = Scr->iconmgr.twm_win->frame;
  2134.             iconwin = Scr->iconmgr.active->w;
  2135.         }
  2136.         } else {
  2137.         for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
  2138.             if (strncmp (action, t->icon_name, len) == 0) {
  2139.             if (t->list && t->list->iconmgr->twm_win->mapped) {
  2140.                 raisewin = t->list->iconmgr->twm_win->frame;
  2141.                 iconwin = t->list->icon;
  2142.                 break;
  2143.             }
  2144.             }
  2145.         }
  2146.         }
  2147.  
  2148.         if (raisewin) {
  2149.         XRaiseWindow (dpy, raisewin);
  2150.         XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
  2151.         } else {
  2152.         XBell (dpy, 0);
  2153.         }
  2154.     }
  2155.     break;
  2156.     
  2157.     case F_WARPRING:
  2158.     switch (action[0]) {
  2159.       case 'n':
  2160.         WarpAlongRing (&eventp->xbutton, True);
  2161.         break;
  2162.       case 'p':
  2163.         WarpAlongRing (&eventp->xbutton, False);
  2164.         break;
  2165.       default:
  2166.         XBell (dpy, 0);
  2167.         break;
  2168.     }
  2169.     break;
  2170.  
  2171.     case F_FILE:
  2172.     action = ExpandFilename(action);
  2173.     fd = open(action, 0);
  2174.     if (fd >= 0)
  2175.     {
  2176.         count = read(fd, buff, MAX_FILE_SIZE - 1);
  2177.         if (count > 0)
  2178.         XStoreBytes(dpy, buff, count);
  2179.  
  2180.         close(fd);
  2181.     }
  2182.     else
  2183.     {
  2184.         fprintf (stderr, "%s:  unable to open file \"%s\"\n", 
  2185.              ProgramName, action);
  2186.     }
  2187.     break;
  2188.  
  2189.     case F_REFRESH:
  2190.     {
  2191.         XSetWindowAttributes attributes;
  2192.         unsigned long valuemask;
  2193.  
  2194.         valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
  2195.         attributes.background_pixel = Scr->Black;
  2196.         attributes.backing_store = NotUseful;
  2197.         attributes.save_under = False;
  2198.         w = XCreateWindow (dpy, Scr->Root, 0, 0,
  2199.                    (unsigned int) Scr->MyDisplayWidth,
  2200.                    (unsigned int) Scr->MyDisplayHeight,
  2201.                    (unsigned int) 0,
  2202.                    CopyFromParent, (unsigned int) CopyFromParent,
  2203.                    (Visual *) CopyFromParent, valuemask,
  2204.                    &attributes);
  2205.         XMapWindow (dpy, w);
  2206.         XDestroyWindow (dpy, w);
  2207.         XFlush (dpy);
  2208.     }
  2209.     break;
  2210.  
  2211.     case F_WINREFRESH:
  2212.     if (DeferExecution(context, func, Scr->SelectCursor))
  2213.         return TRUE;
  2214.  
  2215.     if (context == C_ICON && tmp_win->icon_w)
  2216.         w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
  2217.         0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
  2218.     else
  2219.         w = XCreateSimpleWindow(dpy, tmp_win->frame,
  2220.         0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
  2221.  
  2222.     XMapWindow(dpy, w);
  2223.     XDestroyWindow(dpy, w);
  2224.     XFlush(dpy);
  2225.     break;
  2226.  
  2227.     case F_QUIT:
  2228.     Done();
  2229.     break;
  2230.     }
  2231.  
  2232.     if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
  2233.     return do_next_action;
  2234. }
  2235.  
  2236.  
  2237.  
  2238. /***********************************************************************
  2239.  *
  2240.  *  Procedure:
  2241.  *    DeferExecution - defer the execution of a function to the
  2242.  *        next button press if the context is C_ROOT
  2243.  *
  2244.  *  Inputs:
  2245.  *    context    - the context in which the mouse button was pressed
  2246.  *    func    - the function to defer
  2247.  *    cursor    - the cursor to display while waiting
  2248.  *
  2249.  ***********************************************************************
  2250.  */
  2251.  
  2252. int
  2253. DeferExecution(context, func, cursor)
  2254. int context, func;
  2255. Cursor cursor;
  2256. {
  2257.   if (context == C_ROOT)
  2258.     {
  2259.     LastCursor = cursor;
  2260.     XGrabPointer(dpy, Scr->Root, True,
  2261.         ButtonPressMask | ButtonReleaseMask,
  2262.         GrabModeAsync, GrabModeAsync,
  2263.         Scr->Root, cursor, CurrentTime);
  2264.  
  2265.     RootFunction = func;
  2266.  
  2267.     return (TRUE);
  2268.     }
  2269.     
  2270.     return (FALSE);
  2271. }
  2272.  
  2273.  
  2274.  
  2275. /***********************************************************************
  2276.  *
  2277.  *  Procedure:
  2278.  *    ReGrab - regrab the pointer with the LastCursor;
  2279.  *
  2280.  ***********************************************************************
  2281.  */
  2282.  
  2283. ReGrab()
  2284. {
  2285.     XGrabPointer(dpy, Scr->Root, True,
  2286.     ButtonPressMask | ButtonReleaseMask,
  2287.     GrabModeAsync, GrabModeAsync,
  2288.     Scr->Root, LastCursor, CurrentTime);
  2289. }
  2290.  
  2291.  
  2292.  
  2293. /***********************************************************************
  2294.  *
  2295.  *  Procedure:
  2296.  *    NeedToDefer - checks each function in the list to see if it
  2297.  *        is one that needs to be defered.
  2298.  *
  2299.  *  Inputs:
  2300.  *    root    - the menu root to check
  2301.  *
  2302.  ***********************************************************************
  2303.  */
  2304.  
  2305. NeedToDefer(root)
  2306. MenuRoot *root;
  2307. {
  2308.     MenuItem *mitem;
  2309.  
  2310.     for (mitem = root->first; mitem != NULL; mitem = mitem->next)
  2311.     {
  2312.     switch (mitem->func)
  2313.     {
  2314.     case F_IDENTIFY:
  2315.     case F_RESIZE:
  2316.     case F_MOVE:
  2317.     case F_FORCEMOVE:
  2318.     case F_DEICONIFY:
  2319.     case F_ICONIFY:
  2320.     case F_RAISELOWER:
  2321.     case F_RAISE:
  2322.     case F_LOWER:
  2323.     case F_FOCUS:
  2324.     case F_DESTROY:
  2325.     case F_WINREFRESH:
  2326.     case F_ZOOM:
  2327.     case F_FULLZOOM:
  2328.     case F_HORIZOOM:
  2329.         case F_RIGHTZOOM:
  2330.         case F_LEFTZOOM:
  2331.         case F_TOPZOOM:
  2332.         case F_BOTTOMZOOM:
  2333.     case F_AUTORAISE:
  2334.         return TRUE;
  2335.     }
  2336.     }
  2337.     return FALSE;
  2338. }
  2339.  
  2340.  
  2341.  
  2342. /***********************************************************************
  2343.  *
  2344.  *  Procedure:
  2345.  *    Execute - execute the string by /bin/sh
  2346.  *
  2347.  *  Inputs:
  2348.  *    s    - the string containing the command
  2349.  *
  2350.  ***********************************************************************
  2351.  */
  2352.  
  2353. void
  2354. Execute(s)
  2355.     char *s;
  2356. {
  2357.     static char buf[256];
  2358.     char *ds = DisplayString (dpy);
  2359.     char *colon, *dot1;
  2360.     char oldDisplay[256];
  2361.     char *doisplay;
  2362.     int restorevar = 0;
  2363.  
  2364.     oldDisplay[0] = '\0';
  2365.     doisplay=getenv("DISPLAY");
  2366.     if (doisplay)
  2367.     strcpy (oldDisplay, doisplay);
  2368.  
  2369.     /*
  2370.      * Build a display string using the current screen number, so that
  2371.      * X programs which get fired up from a menu come up on the screen
  2372.      * that they were invoked from, unless specifically overridden on
  2373.      * their command line.
  2374.      */
  2375.     colon = rindex (ds, ':');
  2376.     if (colon) {            /* if host[:]:dpy */
  2377.     strcpy (buf, "DISPLAY=");
  2378.     strcat (buf, ds);
  2379.     colon = buf + 8 + (colon - ds);    /* use version in buf */
  2380.     dot1 = index (colon, '.');    /* first period after colon */
  2381.     if (!dot1) dot1 = colon + strlen (colon);  /* if not there, append */
  2382.     (void) sprintf (dot1, ".%d", Scr->screen);
  2383.     putenv (buf);
  2384.     restorevar = 1;
  2385.     }
  2386.  
  2387.     (void) system (s);
  2388.  
  2389.     if (restorevar) {        /* why bother? */
  2390.     (void) sprintf (buf, "DISPLAY=%s", oldDisplay);
  2391.     putenv (buf);
  2392.     }
  2393. }
  2394.  
  2395.  
  2396.  
  2397. /***********************************************************************
  2398.  *
  2399.  *  Procedure:
  2400.  *    FocusOnRoot - put input focus on the root window
  2401.  *
  2402.  ***********************************************************************
  2403.  */
  2404.  
  2405. void
  2406. FocusOnRoot()
  2407. {
  2408.     SetFocus ((TwmWindow *) NULL, LastTimestamp());
  2409.     if (Scr->Focus != NULL)
  2410.     {
  2411.     SetBorder (Scr->Focus, False);
  2412.     if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
  2413.     }
  2414.     InstallWindowColormaps(0, &Scr->TwmRoot);
  2415.     Scr->Focus = NULL;
  2416.     Scr->FocusRoot = TRUE;
  2417. }
  2418.  
  2419. DeIconify(tmp_win)
  2420. TwmWindow *tmp_win;
  2421. {
  2422.     TwmWindow *t;
  2423.  
  2424.     /* de-iconify the main window */
  2425.     if (tmp_win->icon)
  2426.     {
  2427.     if (tmp_win->icon_on)
  2428.         Zoom(tmp_win->icon_w, tmp_win->frame);
  2429.     else if (tmp_win->group != NULL)
  2430.     {
  2431.         for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
  2432.         {
  2433.         if (tmp_win->group == t->w && t->icon_on)
  2434.         {
  2435.             Zoom(t->icon_w, tmp_win->frame);
  2436.             break;
  2437.         }
  2438.         }
  2439.     }
  2440.     }
  2441.  
  2442.     XMapWindow(dpy, tmp_win->w);
  2443.     tmp_win->mapped = TRUE;
  2444.     if (Scr->NoRaiseDeicon)
  2445.     XMapWindow(dpy, tmp_win->frame);
  2446.     else
  2447.     XMapRaised(dpy, tmp_win->frame);
  2448.     SetMapStateProp(tmp_win, NormalState);
  2449.  
  2450.     if (tmp_win->icon_w) {
  2451.     XUnmapWindow(dpy, tmp_win->icon_w);
  2452.     IconDown (tmp_win);
  2453.     }
  2454.     if (tmp_win->list)
  2455.     XUnmapWindow(dpy, tmp_win->list->icon);
  2456.     if ((Scr->WarpCursor ||
  2457.      LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
  2458.     tmp_win->icon)
  2459.       WarpToWindow (tmp_win);
  2460.     tmp_win->icon = FALSE;
  2461.     tmp_win->icon_on = FALSE;
  2462.  
  2463.  
  2464.     /* now de-iconify transients */
  2465.     for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
  2466.     {
  2467.       if (t->transient && t->transientfor == tmp_win->w)
  2468.         {
  2469.           if (t->icon_on)
  2470.         Zoom(t->icon_w, t->frame);
  2471.           else
  2472.         Zoom(tmp_win->icon_w, t->frame);
  2473.           
  2474.           XMapWindow(dpy, t->w);
  2475.           t->mapped = TRUE;
  2476.           if (Scr->NoRaiseDeicon)
  2477.         XMapWindow(dpy, t->frame);
  2478.           else
  2479.         XMapRaised(dpy, t->frame);
  2480.           SetMapStateProp(t, NormalState);
  2481.           
  2482.           if (t->icon_w) {
  2483.         XUnmapWindow(dpy, t->icon_w);
  2484.         IconDown (t);
  2485.           }
  2486.           if (t->list) XUnmapWindow(dpy, t->list->icon);
  2487.           t->icon = FALSE;
  2488.           t->icon_on = FALSE;
  2489.         }
  2490.     }
  2491.     
  2492.     XSync (dpy, 0);
  2493. }
  2494.  
  2495.  
  2496.  
  2497. Iconify(tmp_win, def_x, def_y)
  2498. TwmWindow *tmp_win;
  2499. int def_x, def_y;
  2500. {
  2501.     TwmWindow *t;
  2502.     int iconify;
  2503.     XWindowAttributes winattrs;
  2504.     unsigned long eventMask;
  2505.  
  2506.     iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
  2507.     if (iconify)
  2508.     {
  2509.     if (tmp_win->icon_w == NULL)
  2510.         CreateIconWindow(tmp_win, def_x, def_y);
  2511.     else
  2512.         IconUp(tmp_win);
  2513.     XMapRaised(dpy, tmp_win->icon_w);
  2514.     }
  2515.     if (tmp_win->list)
  2516.     XMapWindow(dpy, tmp_win->list->icon);
  2517.  
  2518.     XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
  2519.     eventMask = winattrs.your_event_mask;
  2520.  
  2521.     /* iconify transients first */
  2522.     for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
  2523.       {
  2524.     if (t->transient && t->transientfor == tmp_win->w)
  2525.       {
  2526.         if (iconify)
  2527.           {
  2528.         if (t->icon_on)
  2529.             Zoom(t->icon_w, tmp_win->icon_w);
  2530.         else
  2531.           Zoom(t->frame, tmp_win->icon_w);
  2532.           }
  2533.         
  2534.         /*
  2535.          * Prevent the receipt of an UnmapNotify, since that would
  2536.          * cause a transition to the Withdrawn state.
  2537.          */
  2538.         t->mapped = FALSE;
  2539.         XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
  2540.         XUnmapWindow(dpy, t->w);
  2541.         XSelectInput(dpy, t->w, eventMask);
  2542.         XUnmapWindow(dpy, t->frame);
  2543.         if (t->icon_w)
  2544.           XUnmapWindow(dpy, t->icon_w);
  2545.         SetMapStateProp(t, IconicState);
  2546.         SetBorder (t, False);
  2547.         if (t == Scr->Focus)
  2548.           {
  2549.         SetFocus ((TwmWindow *) NULL, LastTimestamp());
  2550.         Scr->Focus = NULL;
  2551.         Scr->FocusRoot = TRUE;
  2552.           }
  2553.         if (t->list) XMapWindow(dpy, t->list->icon);
  2554.         t->icon = TRUE;
  2555.         t->icon_on = FALSE;
  2556.       }
  2557.       } 
  2558.     
  2559.     if (iconify)
  2560.     Zoom(tmp_win->frame, tmp_win->icon_w);
  2561.  
  2562.     /*
  2563.      * Prevent the receipt of an UnmapNotify, since that would
  2564.      * cause a transition to the Withdrawn state.
  2565.      */
  2566.     tmp_win->mapped = FALSE;
  2567.     XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
  2568.     XUnmapWindow(dpy, tmp_win->w);
  2569.     XSelectInput(dpy, tmp_win->w, eventMask);
  2570.     XUnmapWindow(dpy, tmp_win->frame);
  2571.     SetMapStateProp(tmp_win, IconicState);
  2572.  
  2573.     SetBorder (tmp_win, False);
  2574.     if (tmp_win == Scr->Focus)
  2575.     {
  2576.     SetFocus ((TwmWindow *) NULL, LastTimestamp());
  2577.     Scr->Focus = NULL;
  2578.     Scr->FocusRoot = TRUE;
  2579.     }
  2580.     tmp_win->icon = TRUE;
  2581.     if (iconify)
  2582.     tmp_win->icon_on = TRUE;
  2583.     else
  2584.     tmp_win->icon_on = FALSE;
  2585.     XSync (dpy, 0);
  2586. }
  2587.  
  2588.  
  2589.  
  2590. static void Identify (t)
  2591. TwmWindow *t;
  2592. {
  2593.     int i, n, twidth, width, height;
  2594.     int x, y;
  2595.     unsigned int wwidth, wheight, bw, depth;
  2596.     Window junk;
  2597.     int px, py, dummy;
  2598.     unsigned udummy;
  2599.  
  2600.     n = 0;
  2601.     (void) sprintf(Info[n++], "Twm version:  %s", Version);
  2602.     Info[n++][0] = '\0';
  2603.  
  2604.     if (t) {
  2605.     XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
  2606.               &wwidth, &wheight, &bw, &depth);
  2607.     (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
  2608.                       &x, &y, &junk);
  2609.     (void) sprintf(Info[n++], "Name             = \"%s\"", t->full_name);
  2610.     (void) sprintf(Info[n++], "Class.res_name   = \"%s\"", t->class.res_name);
  2611.     (void) sprintf(Info[n++], "Class.res_class  = \"%s\"", t->class.res_class);
  2612.     Info[n++][0] = '\0';
  2613.     (void) sprintf(Info[n++], "Geometry/root    = %dx%d+%d+%d", wwidth, wheight,
  2614.         x, y);
  2615.     (void) sprintf(Info[n++], "Border width     = %d", bw);
  2616.     (void) sprintf(Info[n++], "Depth            = %d", depth);
  2617.     }
  2618.  
  2619.     Info[n++][0] = '\0';
  2620.     (void) sprintf(Info[n++], "Click to dismiss....");
  2621.  
  2622.     /* figure out the width and height of the info window */
  2623.     height = n * (Scr->DefaultFont.height+2);
  2624.     width = 1;
  2625.     for (i = 0; i < n; i++)
  2626.     {
  2627.     twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
  2628.         strlen(Info[i]));
  2629.     if (twidth > width)
  2630.         width = twidth;
  2631.     }
  2632.     if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
  2633.  
  2634.     width += 10;        /* some padding */
  2635.     if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
  2636.                &dummy, &dummy, &udummy)) {
  2637.     px -= (width / 2);
  2638.     py -= (height / 3);
  2639.     if (px + width + BW2 >= Scr->MyDisplayWidth) 
  2640.       px = Scr->MyDisplayWidth - width - BW2;
  2641.     if (py + height + BW2 >= Scr->MyDisplayHeight) 
  2642.       py = Scr->MyDisplayHeight - height - BW2;
  2643.     if (px < 0) px = 0;
  2644.     if (py < 0) py = 0;
  2645.     } else {
  2646.     px = py = 0;
  2647.     }
  2648.     XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
  2649.     XMapRaised(dpy, Scr->InfoWindow); 
  2650.     InfoLines = n;
  2651. }
  2652.  
  2653.  
  2654.  
  2655. SetMapStateProp(tmp_win, state)
  2656. TwmWindow *tmp_win;
  2657. int state;
  2658. {
  2659.     unsigned long data[2];        /* "suggested" by ICCCM version 1 */
  2660.   
  2661.     data[0] = (unsigned long) state;
  2662.     data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None : 
  2663.                tmp_win->icon_w);
  2664.  
  2665.     XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32, 
  2666.          PropModeReplace, (unsigned char *) data, 2);
  2667. }
  2668.  
  2669.  
  2670.  
  2671. Bool GetWMState (w, statep, iwp)
  2672.     Window w;
  2673.     int *statep;
  2674.     Window *iwp;
  2675. {
  2676.     Atom actual_type;
  2677.     int actual_format;
  2678.     unsigned long nitems, bytesafter;
  2679.     unsigned long *datap = NULL;
  2680.     Bool retval = False;
  2681.  
  2682.     if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
  2683.                 &actual_type, &actual_format, &nitems, &bytesafter,
  2684.                 (unsigned char **) &datap) != Success || !datap)
  2685.       return False;
  2686.  
  2687.     if (nitems <= 2) {            /* "suggested" by ICCCM version 1 */
  2688.     *statep = (int) datap[0];
  2689.     *iwp = (Window) datap[1];
  2690.     retval = True;
  2691.     }
  2692.  
  2693.     XFree ((char *) datap);
  2694.     return retval;
  2695. }
  2696.  
  2697.  
  2698.  
  2699. WarpToScreen (n, inc)
  2700.     int n, inc;
  2701. {
  2702.     Window dumwin;
  2703.     int x, y, dumint;
  2704.     unsigned int dummask;
  2705.     ScreenInfo *newscr = NULL;
  2706.  
  2707.     while (!newscr) {
  2708.                     /* wrap around */
  2709.     if (n < 0) 
  2710.       n = NumScreens - 1;
  2711.     else if (n >= NumScreens)
  2712.       n = 0;
  2713.  
  2714.     newscr = ScreenList[n];
  2715.     if (!newscr) {            /* make sure screen is managed */
  2716.         if (inc) {            /* walk around the list */
  2717.         n += inc;
  2718.         continue;
  2719.         }
  2720.         fprintf (stderr, "%s:  unable to warp to unmanaged screen %d\n", 
  2721.              ProgramName, n);
  2722.         XBell (dpy, 0);
  2723.         return;
  2724.     }
  2725.     }
  2726.  
  2727.     if (Scr->screen == n) return;    /* already on that screen */
  2728.  
  2729.     PreviousScreen = Scr->screen;
  2730.     XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
  2731.            &dumint, &dumint, &dummask);
  2732.  
  2733.     XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
  2734.     return;
  2735. }
  2736.  
  2737.  
  2738.  
  2739.  
  2740. /*
  2741.  * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
  2742.  */
  2743.  
  2744. BumpWindowColormap (tmp, inc)
  2745.     TwmWindow *tmp;
  2746.     int inc;
  2747. {
  2748.     int i, j, previously_installed;
  2749.     ColormapWindow **cwins;
  2750.  
  2751.     if (!tmp) return;
  2752.  
  2753.     if (inc && tmp->cmaps.number_cwins > 0) {
  2754.     cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
  2755.                        tmp->cmaps.number_cwins);
  2756.     if (cwins) {        
  2757.         if (previously_installed =
  2758.         /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
  2759.             tmp->cmaps.number_cwins)) {
  2760.         for (i = tmp->cmaps.number_cwins; i-- > 0; )
  2761.             tmp->cmaps.cwins[i]->colormap->state = 0;
  2762.         }
  2763.  
  2764.         for (i = 0; i < tmp->cmaps.number_cwins; i++) {
  2765.         j = i - inc;
  2766.         if (j >= tmp->cmaps.number_cwins)
  2767.             j -= tmp->cmaps.number_cwins;
  2768.         else if (j < 0)
  2769.             j += tmp->cmaps.number_cwins;
  2770.         cwins[j] = tmp->cmaps.cwins[i];
  2771.         }
  2772.  
  2773.         free((char *) tmp->cmaps.cwins);
  2774.  
  2775.         tmp->cmaps.cwins = cwins;
  2776.  
  2777.         if (tmp->cmaps.number_cwins > 1)
  2778.         bzero (tmp->cmaps.scoreboard, 
  2779.                ColormapsScoreboardLength(&tmp->cmaps));
  2780.  
  2781.         if (previously_installed)
  2782.         InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
  2783.     }
  2784.     } else
  2785.     FetchWmColormapWindows (tmp);
  2786. }
  2787.  
  2788.  
  2789.  
  2790. HideIconManager ()
  2791. {
  2792.     SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
  2793.     XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame);
  2794.     if (Scr->iconmgr.twm_win->icon_w)
  2795.       XUnmapWindow (dpy, Scr->iconmgr.twm_win->icon_w);
  2796.     Scr->iconmgr.twm_win->mapped = FALSE;
  2797.     Scr->iconmgr.twm_win->icon = TRUE;
  2798. }
  2799.  
  2800.  
  2801.  
  2802.  
  2803. SetBorder (tmp, onoroff)
  2804.     TwmWindow *tmp;
  2805.     Bool onoroff;
  2806. {
  2807.     if (tmp->highlight) {
  2808.     if (onoroff) {
  2809.         XSetWindowBorder (dpy, tmp->frame, tmp->border);
  2810.         if (tmp->title_w) 
  2811.           XSetWindowBorder (dpy, tmp->title_w, tmp->border);
  2812.     } else {
  2813.         XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
  2814.         if (tmp->title_w) 
  2815.           XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
  2816.     }
  2817.     }
  2818. }
  2819.  
  2820.  
  2821.  
  2822. DestroyMenu (menu)
  2823.     MenuRoot *menu;
  2824. {
  2825.     MenuItem *item;
  2826.  
  2827.     if (menu->w) {
  2828.     XDeleteContext (dpy, menu->w, MenuContext);
  2829.     XDeleteContext (dpy, menu->w, ScreenContext);
  2830.     if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
  2831.     XDestroyWindow(dpy, menu->w);
  2832.     }
  2833.  
  2834.     for (item = menu->first; item; ) {
  2835.     MenuItem *tmp = item;
  2836.     item = item->next;
  2837.     free ((char *) tmp);
  2838.     }
  2839. }
  2840.  
  2841.  
  2842.  
  2843. /*
  2844.  * warping routines
  2845.  */
  2846. void WarpAlongRing (ev, forward)
  2847.     XButtonEvent *ev;
  2848.     Bool forward;
  2849. {
  2850.     TwmWindow *r, *head;
  2851.  
  2852.     if (Scr->RingLeader)
  2853.       head = Scr->RingLeader;
  2854.     else if (!(head = Scr->Ring)) 
  2855.       return;
  2856.  
  2857.     if (forward) {
  2858.     for (r = head->ring.next; r != head; r = r->ring.next) {
  2859.         if (!r || r->mapped) break;
  2860.     }
  2861.     } else {
  2862.     for (r = head->ring.prev; r != head; r = r->ring.prev) {
  2863.         if (!r || r->mapped) break;
  2864.     }
  2865.     }
  2866.  
  2867.     if (r && r != head) {
  2868.     TwmWindow *p = Scr->RingLeader, *t;
  2869.  
  2870.     Scr->RingLeader = r;
  2871.     WarpToWindow (r);
  2872.  
  2873.     if (p && p->mapped &&
  2874.         XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
  2875.         p == t) {
  2876.         p->ring.cursor_valid = True;
  2877.         p->ring.curs_x = ev->x_root - t->frame_x;
  2878.         p->ring.curs_y = ev->y_root - t->frame_y;
  2879.         if (p->ring.curs_x < -p->frame_bw || 
  2880.         p->ring.curs_x >= p->frame_width + p->frame_bw ||
  2881.         p->ring.curs_y < -p->frame_bw || 
  2882.         p->ring.curs_y >= p->frame_height + p->frame_bw) {
  2883.         /* somehow out of window */
  2884.         p->ring.curs_x = p->frame_width / 2;
  2885.         p->ring.curs_y = p->frame_height / 2;
  2886.         }
  2887.     }
  2888.     }
  2889. }
  2890.  
  2891.  
  2892.  
  2893. void WarpToWindow (t)
  2894.     TwmWindow *t;
  2895. {
  2896.     int x, y;
  2897.  
  2898.     if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
  2899.     if (t->ring.cursor_valid) {
  2900.     x = t->ring.curs_x;
  2901.     y = t->ring.curs_y;
  2902.     } else {
  2903.     x = t->frame_width / 2;
  2904.     y = t->frame_height / 2;
  2905.     }
  2906.     XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
  2907. }
  2908.  
  2909.  
  2910.  
  2911.  
  2912. /*
  2913.  * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
  2914.  * client messages will have the following form:
  2915.  *
  2916.  *     event type    ClientMessage
  2917.  *     message type    _XA_WM_PROTOCOLS
  2918.  *     window        tmp->w
  2919.  *     format        32
  2920.  *     data[0]        message atom
  2921.  *     data[1]        time stamp
  2922.  */
  2923. static void send_clientmessage (w, a, timestamp)
  2924.     Window w;
  2925.     Atom a;
  2926.     Time timestamp;
  2927. {
  2928.     XClientMessageEvent ev;
  2929.  
  2930.     ev.type = ClientMessage;
  2931.     ev.window = w;
  2932.     ev.message_type = _XA_WM_PROTOCOLS;
  2933.     ev.format = 32;
  2934.     ev.data.l[0] = a;
  2935.     ev.data.l[1] = timestamp;
  2936.     XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
  2937. }
  2938.  
  2939. SendDeleteWindowMessage (tmp, timestamp)
  2940.     TwmWindow *tmp;
  2941.     Time timestamp;
  2942. {
  2943.     send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
  2944. }
  2945.  
  2946. SendSaveYourselfMessage (tmp, timestamp)
  2947.     TwmWindow *tmp;
  2948.     Time timestamp;
  2949. {
  2950.     send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
  2951. }
  2952.  
  2953.  
  2954. SendTakeFocusMessage (tmp, timestamp)
  2955.     TwmWindow *tmp;
  2956.     Time timestamp;
  2957. {
  2958.     send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
  2959. }
  2960.